Spring 中读取文件
Java资源路径的问题
参考资料 Java 项目读取 resources 资源文件路径那点事
实际上可以通过类加载路径来取得资源加载路径
System.out.println(Temp.class.getResource(""));
// file:/D:/JavaProject/study-java/studySocket/target/classes/com/alsritter/
System.out.println(Temp.class.getClassLoader().getResource(""));
// file:/D:/JavaProject/study-java/studySocket/target/classes/
所以要读取项目内的文件,一般是通过获取类加载路径的方式来取得资源路径,其实可以直接取得路径,无需先调用类加载器
// 直接这样写就好了
InputStream fileReader = JdbcUtils.class.getResourceAsStream("/urlPath.properties");
class.getResourceAStream()
与class.getClassLoader().getResorceAsStream()
的区别1) InputStream inStream = PropertiesTest.class.getResourceAsStream("test.properties");
2) inStream = PropertiesTest.class.getResourceAsStream("/com/test/demo/test.properties")
3) inStream = PropertiesTest.class.getClassLoader().getResourceAsStream("com/test/demo/test.properties");
```java
// 之所以要封装一个方法无疑还是方便客户端的调用,省的每次获取 ClassLoader 才能加载资源文件的麻烦!
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
所以直接 getResourceAsStream
实际上内部也是调用 getClassLoader().getResourceAsStream
加载资源 Demo
public class Temp {
public static void main(String[] args) throws IOException {
URL resource = Temp.class.getClassLoader().getResource("./temp.txt");
// file:/D:/JavaProject/study-java/studySocket/target/classes/temp.txt
try (FileInputStream fis = new FileInputStream(resource.getPath());
InputStreamReader isr = new InputStreamReader(fis, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(isr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
}
资源(Resource)接口
很多情况下自己写读取资源文件,都是通过 I/O 相关的类,File,InputStream,OutPutStream 这些,而 Spring 作为一个通用框架,肯定提供了资源读取的工具类
Spring 提供了一个 org.springframework.core.io.Resource
接口,同时 Spring 提供了若干 Resource 接口的实现类,这些实现类可以轻松地加载不同类型的底层资源,并提供了获取文件名、URL 地址以及资源内容的操作方法。
- UrlResource
- ClassPathResource
- FileSystemResource
- ServletContextResource
- InputStreamResource
- ByteArrayResource
可以指定不同的前缀来创建路径以从不同位置加载资源
前缀 | 示例 | 说明 |
---|---|---|
classpath: | classpath:com/myapp/config.xml | 从类路径加载 |
file: | file:///data/config.xml | 从文件系统作为URL加载。 |
http: | https://myserver/logo.png | 从URL加载 |
(none) | /data/config.xml | 取决于底层的 ApplicationContext |
ResourceLoaderAware 接口使用
它用于加载资源(例如类路径或文件系统资源)。
//Expose the ClassLoader used by this ResourceLoader.
ClassLoader getClassLoader()
//Return a Resource handle for the specified resource location.
Resource getResource(String location)
getResource()
方法将根据资源路径决定要实例化的 Resource 实现。 这个 ResourceLoader 需要实现 ResourceLoaderAware 接口。
ResourceLoader 有如下两种方法取得:
使用 ApplicationContext 的方式
在 Spring 中,所有应用程序上下文都实现 ResourceLoader 接口。因此,所有应用程序上下文都可用于获取资源实例。
这个 ApplicationContext 实现了 ApplicationContextAware 接口。
@Autowired
private ApplicationContext ctx;
Resource banner = ctx.getResource("file:c:/temp/filesystemdata.txt");
// 或者
Resource banner = ctx.getResource("classpath:filesystemdata.txt");
下同
使用 ResourceLoader 的方式
@Autowired
private ResourceLoader resourceLoader;
Resource banner = resourceLoader.getResource("file:c:/temp/filesystemdata.txt");
指定使用工具类
上面使用自动注入的方式取得的 ResourceLoader 会自动根据输入的地址选择合适的工具类加载资源,如果想要自己指定也可以使用如下两种方式(其它就不列了,大同小异)
使用 ClassPathResource 类读取
@RestController
public class TestController {
@RequestMapping("testFile")
public String testFile() throws IOException {
// ClassPathResource类的构造方法接收路径名称,自动去classpath路径下找文件
ClassPathResource classPathResource = new ClassPathResource("test.txt");
// 获得File对象,当然也可以获取输入流对象
File file = classPathResource.getFile();
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
StringBuilder content = new StringBuilder();
String line = null;
while ((line = bufferedReader.readLine()) != null) {
content.append(line);
}
return content.toString();
}
}
使用 FileSystemResource 类读取文件
FileSystemResource 这个类在找文件的时候就是按照给定的路径名去找,默认的当前目录就是项目根目录。
使用该类来查找文件时,需要保证文件路径完全正确,另外,在代码中将路径写死是一个不好的习惯,特别是一个文件的路径在不同的主机上的位置(层级目录)不一定相同,所以我们开发过程中很少使用这种方式。
FileSystemResource 的用法和 ClassPathResource 的用法相似,因为他们都继承了 AbstractResource 这个抽象类。
public class FileTest extends ApplicationConfigTest {
@Test
public void testFile() throws IOException {
FileSystemResource resource = new FileSystemResource("./");
System.out.println(resource.getFile().getAbsolutePath());
// 传入当前路径,获得的是项目根目录:/Users/ganlixin/code/Spring/demo/example/.
// 传入根目录路径,获得的就是操作系统的根目录
resource = new FileSystemResource("/");
System.out.println(resource.getFile().getAbsolutePath()); // 输出 /
// 获取单元测试resources目录下的test.txt,需要指定详细的路径
resource = new FileSystemResource("src/test/resources/test.txt");
final File file = resource.getFile();
final BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
System.out.println(line);
}
}
}
无法读取打包到 jar 包里面的资源
在开发环境中,使用 ResourceUtils.getFile(“classpath:static/files/8k.wav”)
能读取到 File ,结果打包发布后,读取不了。主要问题是 ClassPathResource 只能读文件,jar 包中的已经不算文件了,所以 getFile 会报错,只能使用 getInputStream
如果要在 Spring Boot JAR 中从类路径加载文件,则必须使用该
resource.getInputStream()
方法将其作为 InputStream 进行检索。如果尝试使用,resource.getFile()
将收到错误,因为 Spring 尝试访问文件系统路径,但它无法访问 JAR 中的路径。
解决方法
//方式1:
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(fileName)
//方式2:
public static String getFile(String filePath) {
ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource=resourceLoader.getResource("classpath:"+filePath);
StringBuffer strBuff = new StringBuffer();
try (InputStream inputStream = resource.getInputStream()) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String string = null;
while ((string = bufferedReader.readLine()) != null) {
strBuff.append(string);
}
} catch (Exception e) {
e.printStackTrace();
}
return strBuff.toString();
}
使用示例:
private String jsonFile;
@Autowired
private ApplicationContext ctx;
/**
* 构造方法执行之后,调用此方法
* 这里读取文件
*/
@PostConstruct
public void init() throws IOException {
Resource resource = ctx.getResource("classpath:testData.json");
StringBuilder content = new StringBuilder();
try (InputStream inputStream = resource.getInputStream()) {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String string = null;
while ((string = bufferedReader.readLine()) != null) {
content.append(string);
}
} catch (Exception e) {
e.printStackTrace();
}
log.info("启动时加载了文件");
jsonFile = content.toString();
}
Reference
springboot读取jar包resources下的文件 参考资料 Spring项目读取resource下的文件 参考资料 Spring系列八:Spring 中读取文件-ResourceLoaderAware